/*******************************************************************************
 *   Filename:       bsp_sht2x_iic.c
 *   Revised:        All copyrights reserved to Roger-WY.
 *   Revision:       v1.0
 *   Writer:	     Roger-WY.
 *
 *   Description:    SHT2X温湿度传感器模块驱动
 *                   使用模拟IIC读取数据
 *   Notes:
 *     				E-mail:261313062@qq.com
 *
 *******************************************************************************/
#include "bsp_sht2x_iic.h"
#include "bsp_timer.h"
#ifdef SHT2X_USE_HARD_I2C
#include "bsp_cpu_i2c2.h"
#endif




#ifndef  SHT2X_USE_HARD_I2C
#define SHT2X_DELAY_US(a)   bsp_DelayUS(a)
/*
********************************************************************************
*	函 数 名: SHT2x_Delay
*	功能说明: I2C总线位延迟，最快400KHz
*	形    参:  无
*	返 回 值: 无
********************************************************************************
*/
static void SHT2x_Delay(void)
{
    volatile uint8_t i = 0;

    for(i = 0; i < 50; i++);
}


void bsp_Sht2xGpioInit(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    SHT2X_SCL_RCC();
    SHT2X_SDA_RCC();	/* 打开GPIO时钟 */

    /*Configure GPIO pins */
    GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull  = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Pin = SHT2X_SCL_PIN;
    HAL_GPIO_Init(SHT2X_SCL_PORT, &GPIO_InitStruct);
    GPIO_InitStruct.Pin = SHT2X_SDA_PIN;
    HAL_GPIO_Init(SHT2X_SDA_PORT, &GPIO_InitStruct);
}


/*******************************************************************************
* 名    称： SHT2x_i2c_Start
* 功    能： CPU发起I2C总线启动信号
* 入口参数： 无
* 出口参数： 无
* 作　　者： Roger-WY
* 创建日期： 2017-01-22
* 修    改：
* 修改日期：
* 备    注：  开始时序
 *            SCL ˉˉˉˉˉˉ\____
 *            SDA ˉˉˉˉ\______
 *                  |   |
 *                  START
*******************************************************************************/
static void SHT2x_i2c_Start(void)
{
    /* 设置SCL和SDA的IO方向--此处设置为输出 */
    SHT2X_SDA_OUTPUTMODE();
    SHT2X_SCL_OUTPUTMODE();
    /* 当SCL高电平时，SDA出现一个下跳沿表示I2C总线启动信号 */
    SHT2X_SDA_1();
    SHT2X_SCL_1();
    SHT2x_Delay();

    SHT2X_SDA_0();
    SHT2x_Delay();
    SHT2X_SCL_0();
    SHT2x_Delay();
}

/*******************************************************************************
* 名    称： SHT2x_i2c_Stop
* 功    能： CPU发起I2C总线停止信号
* 入口参数： 无
* 出口参数： 无
* 作　　者： Roger-WY
* 创建日期： 2017-01-22
* 修    改：
* 修改日期：
* 备    注： 停止时序
 *            SCL _____/ˉˉˉˉˉˉˉ
 *            SDA _________/ˉˉˉˉˉ
 *                       |   |
 *                       STOP
*******************************************************************************/
static void SHT2x_i2c_Stop(void)
{
    /* 设置SCL和SDA的IO方向--此处设置为输出 */
    SHT2X_SDA_OUTPUTMODE();
    SHT2X_SCL_OUTPUTMODE();
    /* 当SCL高电平时，SDA出现一个上跳沿表示I2C总线停止信号 */
    SHT2X_SDA_0();
    SHT2X_SCL_1();
    SHT2x_Delay();
    SHT2X_SDA_1();
    SHT2x_Delay();
}

/*******************************************************************************
* 名    称： bsp_i2c_SendByte
* 功    能： CPU向I2C总线设备发送8bit数据
* 入口参数：  _ucByte ： 等待发送的字节
* 出口参数： 无
* 作　　者： Roger-WY
* 创建日期： 2017-01-22
* 修    改：
* 修改日期：
* 备    注：
*******************************************************************************/
static void SHT2x_i2c_SendByte(uint8_t _ucByte)
{
    uint8_t i;
    /* 设置SCL和SDA的IO方向--此处设置为输出 */
    SHT2X_SDA_OUTPUTMODE();
    SHT2X_SCL_OUTPUTMODE();
    /* 先发送字节的高位bit7 */
    for(i = 0; i < 8; i++)
    {
        if(_ucByte & 0x80)
        {
            SHT2X_SDA_1();
        }
        else
        {
            SHT2X_SDA_0();
        }
        SHT2x_Delay();
        SHT2X_SCL_1();
        SHT2x_Delay();
        SHT2X_SCL_0();
        if(i == 7)
        {
            SHT2X_SDA_1(); // 释放总线
        }
        _ucByte <<= 1;	/* 左移一个bit */
        SHT2x_Delay();
    }
}

/*******************************************************************************
* 名    称： bsp_i2c_ReadByte
* 功    能： CPU从I2C总线设备读取8bit数据
* 入口参数： 无
* 出口参数： 读到的数据
* 作　　者： Roger-WY
* 创建日期： 2017-01-22
* 修    改：
* 修改日期：
* 备    注：
*******************************************************************************/
static uint8_t SHT2x_i2c_ReadByte(void)
{
    uint8_t i;
    uint8_t value;
    /* 设置SCL和SDA的IO方向--此处SCL设置为输出 SDA设置为输入*/
    SHT2X_SDA_INPUTMODE();
    SHT2X_SCL_OUTPUTMODE();
    /* 读到第1个bit为数据的bit7 */
    value = 0;
    for(i = 0; i < 8; i++)
    {
        value <<= 1;
        SHT2X_SCL_1();
        SHT2x_Delay();
        if(SHT2X_SDA_READ())
        {
            value ++;
        }
        SHT2X_SCL_0();
        SHT2x_Delay();
    }
    return value;
}

/*******************************************************************************
* 名    称： SHT2x_i2c_WaitAck
* 功    能： CPU产生一个时钟，并读取器件的ACK应答信号
* 入口参数： 无
* 出口参数： 返回0表示正确应答，1表示无器件响应
* 作　　者： Roger-WY
* 创建日期： 2017-01-22
* 修    改：
* 修改日期：
* 备    注：
*******************************************************************************/
static uint8_t SHT2x_i2c_WaitAck(void)
{
    uint8_t re;
    /* 设置SCL和SDA的IO方向--此处SCL设置为输出 SDA设置为输入*/
    SHT2X_SDA_INPUTMODE();
    SHT2X_SCL_OUTPUTMODE();
    SHT2X_SDA_1();	/* CPU释放SDA总线 */
    SHT2x_Delay();
    SHT2X_SCL_1();	/* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
    SHT2x_Delay();
    if(SHT2X_SDA_READ())  	/* CPU读取SDA口线状态 */
    {
        re = 1;
    }
    else
    {
        re = 0;
    }
    SHT2X_SCL_0();
    SHT2x_Delay();
    return re;
}

/*******************************************************************************
* 名    称： SHT2x_i2c_Ack
* 功    能： CPU产生一个ACK信号
* 入口参数： 无
* 出口参数： 无
* 作　　者： Roger-WY
* 创建日期： 2017-01-22
* 修    改：
* 修改日期：
* 备    注：
*******************************************************************************/
static void SHT2x_i2c_Ack(void)
{
    /* 设置SCL和SDA的IO方向--此处设置为输出 */
    SHT2X_SDA_OUTPUTMODE();
    SHT2X_SCL_OUTPUTMODE();
    SHT2X_SDA_0();	/* CPU驱动SDA = 0 */
    SHT2x_Delay();
    SHT2X_SCL_1();	/* CPU产生1个时钟 */
    SHT2x_Delay();
    SHT2X_SCL_0();
    SHT2x_Delay();
    SHT2X_SDA_1();	/* CPU释放SDA总线 */
}

/*******************************************************************************
* 名    称： SHT2x_i2c_NAck
* 功    能： CPU产生1个NACK信号。
* 入口参数： 无
* 出口参数： 无
* 作　　者： Roger-WY
* 创建日期： 2017-01-22
* 修    改：
* 修改日期：
* 备    注：
*******************************************************************************/
static void SHT2x_i2c_NAck(void)
{
    /* 设置SCL和SDA的IO方向--此处设置为输出 */
    SHT2X_SDA_OUTPUTMODE();
    SHT2X_SCL_OUTPUTMODE();
    SHT2X_SDA_1();	/* CPU驱动SDA = 1 */
    SHT2x_Delay();
    SHT2X_SCL_1();	/* CPU产生1个时钟 */
    SHT2x_Delay();
    SHT2X_SCL_0();
    SHT2x_Delay();
}

/*******************************************************************************
* 名    称： SHT2x_SendByte
* 功    能： 发送一个字节，并查看从机是否应答
* 入口参数： byte：需要发送的字节
* 出口参数： 发送字节后，查看是否由应答信号。   0：无应答信号（异常）   1：有应答信号（正常）
* 作　　者： Roger-WY
* 创建日期： 2017-01-22
* 修    改：
* 修改日期：
* 备    注：
*******************************************************************************/
static uint8_t SHT2x_SendByte(uint8_t byte)  	//数据从高位到低位
{
    uint8_t  ack     = 0;

    /***********************************************
    * 描述：发送数据
    */
    SHT2x_i2c_SendByte(byte);
    /***********************************************
    * 描述：检查应答
    */
    ack = SHT2x_i2c_WaitAck();

    if(ack)                                     // 检测应答信号
        return (0);                             // NACK返回
    else
        return (1);                             // ACK返回
}

/*******************************************************************************
* 名    称： SHT2x_RecvByte
* 功    能： 接收一个字节，并发送应答或者非应答信号给从机。
* 入口参数： ack  是否发送应答 0：发送应答信号  1：发送非应答信号
*            *dat i2c读取到的字节
* 出口参数： 无
* 作　　者： Roger-WY
* 创建日期： 2017-01-22
* 修    改：
* 修改日期：
* 备    注：
*******************************************************************************/
static uint8_t SHT2x_RecvByte(uint8_t ack, uint8_t* dat)  	//数据从高位到低位
{
    /***********************************************
    * 描述：接收数据
    */
    *dat = SHT2x_i2c_ReadByte();

    /***********************************************
    * 描述：发送或者非应答信号应答信号
    */
    if(ack == 0)
    {
        SHT2x_i2c_Ack();
    }
    else if(ack == 1)
    {
        SHT2x_i2c_NAck();
    }

    return (1);                            	       // Return 8-bit data byte
}
#endif

/*******************************************************************************
* 名    称： bsp_SHT20WrSingleCmd
* 功    能： SHT2X写一个单指令。
* 入口参数： 无
* 出口参数： 无
* 作　　者： Roger-WY
* 创建日期： 2017-01-22
* 修    改：
* 修改日期：
* 备    注：
*******************************************************************************/
uint8_t bsp_SHT2XWrSingleCmd(uint8_t ucSlaveAddr, uint8_t _ucRegAddr, uint8_t _ucRegData)
{
    uint8_t _ucAck = 0;
#ifdef SHT2X_USE_HARD_I2C
    Sensors_I2C2_WriteRegister(ucSlaveAddr,
                               _ucRegAddr,
                               1,
                               &_ucRegData);
#else
    SHT2x_i2c_Start();                            //起始信号
    _ucAck = SHT2x_SendByte(ucSlaveAddr);    //发送设备地址+写信号
    if(!_ucAck)
    {
        goto exit;                                  //器件无响应
    }
    _ucAck = SHT2x_SendByte(_ucRegAddr);          //内部寄存器地址，请参考中文pdf
    if(!_ucAck)
    {
        goto exit;                                  //器件无响应
    }
    _ucAck = SHT2x_SendByte(_ucRegData);      //内部寄存器数据，请参考中文pdf
    if(!_ucAck)
    {
        goto exit;                                  //器件无响应
    }
exit:
    SHT2x_i2c_Stop();                             //发送停止信号
#endif
    return _ucAck;
}

/*******************************************************************************
* 名    称： bsp_SHT20RdData
* 功    能： 读取寄存器数据。
* 入口参数： uint8_t _ucRegAddr： 需要读取的寄存器起始地址
*            uint8_t *_pRegData： 读出来的数据缓存数组
*            uint8_t _ucRegCnt ： 需要读取的寄存器个数
* 出口参数： 无
* 作　　者： Roger-WY
* 创建日期： 2017-01-22
* 修    改：
* 修改日期：
* 备    注：
*******************************************************************************/
uint8_t bsp_SHT2XRdRegData(uint8_t ucSlaveAddr, uint8_t _ucRegAddr, uint8_t* _pRegData, uint8_t _ucRegCnt)
{
    uint8_t  _ucAck = 0;
#ifdef SHT2X_USE_HARD_I2C
    Sensors_I2C2_ReadRegister(ucSlaveAddr,
                              _ucRegAddr,
                              _ucRegCnt,
                              (unsigned char*)_pRegData);
#else
    SHT2x_i2c_Start();                        //起始信号
    _ucAck = SHT2x_SendByte(ucSlaveAddr);//发送设备地址+写信号
    if(!_ucAck)
    {
        goto exit;                                  //器件无响应
    }
    _ucAck = SHT2x_SendByte(_ucRegAddr);
    if(!_ucAck)
    {
        goto exit;                                  //器件无响应
    }
    for(uint16_t i = 0; i < 50; i++)
    {
        SHT2x_i2c_Start();
        _ucAck = SHT2x_SendByte(ucSlaveAddr + 1);   //读
        if(_ucAck == 1)
        {
            break;
        }
        else
        {
            bsp_DelayMS(2);
        }
    }
     if(_ucAck == 1)
     {
        for(uint8_t i = 0; i < _ucRegCnt ; i++)
        {
            if(i == (_ucRegCnt - 1))
            {
                SHT2x_RecvByte(1, _pRegData);     //读完数据之后不发送应答信号
            }
            else
            {
                SHT2x_RecvByte(0, _pRegData);     //读完数据之后发送应答信号
                _pRegData++;
            }
        }
    }
exit:
    SHT2x_i2c_Stop();                         //发送停止信号
#endif
    return _ucAck;
}

/*******************************************************************************
* 名    称： bsp_Sht2xInit
* 功    能： SHT20初始化
* 入口参数：
* 出口参数： 应答
* 作　　者： Roger-WY
* 创建日期： 2017-11-28
* 修    改：
* 修改日期：
* 备    注：
*******************************************************************************/
uint8_t bsp_Sht2xInit(void)
{
    uint8_t _ucAck = 0;
    #ifdef SHT2X_USE_HARD_I2C
    hal_I2c2Master_Init();
    #else
    bsp_Sht2xGpioInit();
    #endif

    return _ucAck;
}

/*******************************************************************************
 * 名    称： SHT_get_hum
 * 功    能： 读SHT20的湿度值
 * 入口参数： 无
 * 出口参数： 当前湿度
 * 作　　者： Roger-WY
 * 创建日期： 2017-11-28
 * 修    改：
 * 修改日期：
 * 备    注：   存储的温度是14位的，
 *              计算时，STAT位计置0
 *
 *                      |--------------LSB------------------|---STAT----|
 *              低字节  | 2^7 | 2^6 | 2^5 | 2^4 | 2^3 | 2^2 | 2^1 | 2^0 |
 *
 *
 *                      |------------------------MSB--------------------------|
 *              高字节  | 2^15 | 2^14 | 2^13 | 2^12 | 2^11 | 2^10 | 2^9 | 2^8 |
 *
 *              温度 = (dat*175.72)/65536-46.85;
 *******************************************************************************/
static float SHT_get_temp(void)
{
    unsigned int dat = 0;
    unsigned char receive[3];
    float temp = 0;

    if(bsp_SHT2XRdRegData(SHT2X_I2C_ADDR, NO_HOLD_AT_START, receive, 3) == 1)
    {
        dat = (receive[0] << 8) | (receive[1] &= 0xfc);
        temp = (dat * 175.72) / 65536 - 46.85;
    }
    else
    {
        temp = 0;
    }

    return temp;
}

/*******************************************************************************
 * 名    称： SHT_get_hum
 * 功    能： 读SHT20的湿度值
 * 入口参数： 无
 * 出口参数： 当前湿度
 * 作　　者： Roger-WY
 * 创建日期： 2017-11-28
 * 修    改：
 * 修改日期：
 * 备    注：   存储的湿度是12位的，
 *              计算时，STAT位计置0
 *
 *                      |--------------LSB------------------|---STAT----|
 *              低字节  | 2^7 | 2^6 | 2^5 | 2^4 | 2^3 | 2^2 | 2^1 | 2^0 |
 *
 *
 *                      |------------------------MSB--------------------------|
 *              高字节  | 2^15 | 2^14 | 2^13 | 2^12 | 2^11 | 2^10 | 2^9 | 2^8 |
 *
 *              湿度 = (dat*125.0)/65536.0-6;
 *******************************************************************************/
static float SHT_get_hum(void)
{
    unsigned int dat = 0;
    unsigned char receive[3];
    float hum = 0;

    if(bsp_SHT2XRdRegData(SHT2X_I2C_ADDR, NO_HOLD_AH_START, receive, 3) == 1)
    {
        dat = (receive[0] << 8) | (receive[1] &= 0xfc);
        hum = (dat * 125.0) / 65536.0 - 6;
    }
    else
    {
        hum = 0;
    }

    return hum;
}

uint8_t bsp_Sht2xMeasure(ShtValueTypeDef* pshtval)
{
    float tTemp = 0;
    float tHumi = 0;

    tTemp = SHT_get_temp();
    tHumi = SHT_get_hum();
    /* 浮点的值 */
//     pshtval->fTemp = tTemp;
//     pshtval->fHumi = tHumi;
#if  1
    /* 放大10倍之后的整型值 */
    pshtval->iTemperature = (int16_t)(tTemp * 10);
    pshtval->uiHumidity   = (int16_t)(tHumi * 10);
#else
    /* 实际的温湿度值直接转为整型 */
    pshtval->iTemperature = (int16_t)(tTemp);
    pshtval->uiHumidity   = (int16_t)(tHumi);
#endif

    return 0;

}